package com.cskaoyan.search.service;

import com.cskaoyan.mall.dto.ProductDto;
import com.cskaoyan.search.converter.ProductConverter;
import com.cskaoyan.search.dto.SearchResponse;
import com.cskaoyan.search.entity.ItemDocument;
import com.cskaoyan.search.form.SearchRequest;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @Description:
 * @since: 2022-11-01 23:09
 * @author: lazy
 */
@Service
public class ProductSearchServiceImpl implements ProductSearchService {

    @Autowired
    RestHighLevelClient client;

    @Autowired
    ElasticsearchRestTemplate restTemplate;

    @Autowired
    ProductConverter productConverter;

    /**
     * 搜索商品 精准搜索
     *
     * @param request request
     * @return SearchResponse
     */
    @Override
    public SearchResponse search(SearchRequest request) {

        // 该Builder包含所有搜索请求的参数
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 获取bool查询Builder
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 构造bool查询中match查询
        MatchQueryBuilder matchQuery = QueryBuilders.matchQuery("title", request.getKey());

        // 将该查询加入bool查询must中
        boolQueryBuilder.must(matchQuery);
        // 构造bool查询中的范围查询
        RangeQueryBuilder priceRange = QueryBuilders.rangeQuery("price");
        priceRange.gte(request.getPriceGt());
        priceRange.lt(request.getPriceLte());
        // 将范围查询添加到bool查询的filter中
        boolQueryBuilder.filter(priceRange);
        // 将bool查询添加到NativeSearchQueryBuilder
        queryBuilder.withQuery(boolQueryBuilder);
        // 构造分页参数
        Sort sort = null;
        if(request.getSort().toString() != ""){
            if (Integer.parseInt(request.getSort()) == 1) {
                sort = Sort.by(Sort.Direction.ASC, "price");
            } else if (Integer.parseInt(request.getSort()) == -1) {
                sort = Sort.by(Sort.Direction.DESC, "price");
            }
        }

        //PageRequest price = PageRequest.of(0, 10, Sort.by(Sort.Order.desc("price")));
        PageRequest price = PageRequest.of(request.getPage() - 1, request.getSize());
        // 向NativeSearchQueryBuilder添加分页参数
        queryBuilder.withPageable(price);
        // 构造高亮参数
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title").preTags("<font color='red'>").postTags("</font>");
        // 向NativeSearchQueryBuilder添加高亮参数
        queryBuilder.withHighlightBuilder(highlightBuilder);
        //queryBuilder.withSort(new ScoreSortBuilder());

        // 使用ElasticsearchRestTemplate发起搜索请求
        NativeSearchQuery build = queryBuilder.build();
        SearchHits<ItemDocument> search = restTemplate.search(build, ItemDocument.class);

        // 获取满足条件的总文档数量
        long totalHits = search.getTotalHits();
        SearchResponse<ProductDto> searchResponse = new SearchResponse<>();
        //将totalHits赋值给searchResponse的成员变量
        searchResponse.setTotal(totalHits);

        // 获取包含所有命中文档的SearchHit对象
        List<SearchHit<ItemDocument>> searchHits = search.getSearchHits();
        ArrayList<ProductDto> productDtos = new ArrayList<>();

        for (SearchHit<ItemDocument> searchHit : searchHits) {
            ItemDocument itemDocument = searchHit.getContent();
            ProductDto productDto = productConverter.item2Dto(itemDocument);

            //将productDto加入到list中
            productDtos.add(productDto);
        }
        searchResponse.setData(productDtos);
        return searchResponse;
    }

    /**
     * 搜索商品
     *
     * @param request request
     * @return SearchResponse
     */
    @Override
    public SearchResponse fuzzySearch(SearchRequest request) throws IOException {

        //该Builder包含所有搜索请求的参数
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

        // 构造具体查询
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", request.getKey());
        //将match查询添加到NativeSearchQueryBuilder
        queryBuilder.withQuery(matchQueryBuilder);

        //构造分页参数
        PageRequest pageRequest = PageRequest.of(request.getPage(), request.getSize());
        queryBuilder.withPageable(pageRequest);

        //构造高亮参数
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title").preTags("<font color='red'>").postTags("</font>");

        //向NativeSearchQueryBuilder添加高亮参数
        queryBuilder.withHighlightBuilder(highlightBuilder);

        //使用ElasticSearchRestTemplate发起搜索请求
        NativeSearchQuery build = queryBuilder.build();
        SearchHits<ItemDocument> search = restTemplate.search(build, ItemDocument.class);

        //获取满足条件的文档数量
        long totalHits = search.getTotalHits();
        SearchResponse<ProductDto> searchResponse = new SearchResponse<>();

        //将totalHits赋值给searchResponse的成员变量
        searchResponse.setTotal(totalHits);

        //获取包含所有命中文档的SearchHit对象
        List<SearchHit<ItemDocument>> searchHits = search.getSearchHits();
        ArrayList<ProductDto> productDtos = new ArrayList<>();
        for (SearchHit<ItemDocument> searchHit : searchHits) {
            ItemDocument itemDocument = searchHit.getContent();
            ProductDto productDto = productConverter.item2Dto(itemDocument);

            //将productDto加入到List当中
            productDtos.add(productDto);
        }
        searchResponse.setData(productDtos);
        return searchResponse;

    }
}
